﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace CommunicateBetweenJsAndCSharp
{
    using Chromium;
    using Chromium.Remote;
    using Chromium.Remote.Event;
    using GRPCDemo;
    using MyDevelopTool;
    using NetDimension.NanUI;
    using Newtonsoft.Json;
    using SiteManager;
    using System.Diagnostics;
    using System.IO;
    using System.Threading;

    public partial class Form1 : WinFormium
    {
        public Form1() : base("http://res.app.local/pages/index.html")
        {
            InitializeComponent();

            LoadHandler.OnLoadEnd += LoadHandler_OnLoadEnd;

            //register the "my" object
            var myObject = GlobalObject.AddObject("my");

            //add property "name" to my, you should implemnt the getter/setter of name property by using PropertyGet/PropertySet events.
            var nameProp = myObject.AddDynamicProperty("name");
            nameProp.PropertyGet += (prop, args) =>
            {
                // getter - if js code "my.name" executes, it'll get the string "NanUI". 
                args.Retval = CfrV8Value.CreateString("NanUI");
                args.SetReturnValue(true);
            };
            nameProp.PropertySet += (prop, args) =>
            {
                // setter's value from js context, here we do nothing, so it will store or igrone by your mind.
                var value = args.Value;
                args.SetReturnValue(true);
            };


            //add a function showCSharpMessageBox
            var showMessageBoxFunc = myObject.AddFunction("showCSharpMessageBox");
            showMessageBoxFunc.Execute += (func, args) =>
            {
                //it will be raised by js code "my.showCSharpMessageBox(`some text`)" executed.
                //get the first string argument in Arguments, it pass by js function.
                var stringArgument = args.Arguments.FirstOrDefault(p => p.IsString);

                if (stringArgument != null)
                {
                    MessageBox.Show(this, stringArgument.StringValue, "C# Messagebox", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
            };

            //add a function getObjectFromCSharp, this function has no arguments, but it will return a Object to js context.
            var getObjectFormCSFunc = myObject.AddFunction("getObjectFromCSharp");
            getObjectFormCSFunc.Execute += (func, args) =>
            {
                //create the CfrV8Value object and the accssor of this Object.
                var jsObjectAccessor = new CfrV8Accessor();
                var jsObject = CfrV8Value.CreateObject(jsObjectAccessor);

                //create a CfrV8Value array
                var jsArray = CfrV8Value.CreateArray(5);

                for (int i = 0; i < 5; i++)
                {
                    jsArray.SetValue(i, CfrV8Value.CreateString(i.ToString()));
                }

                jsObject.SetValue("libName", CfrV8Value.CreateString("NanUI"), CfxV8PropertyAttribute.ReadOnly);
                jsObject.SetValue("friends", jsArray, CfxV8PropertyAttribute.DontDelete);


                args.SetReturnValue(jsObject);

                //in js context, use code "my.getObjectFromCSharp()" will get an object like { friends:["Mr.JSON", "Mr.Lee", "Mr.BONG"], libName:"NanUI" }
            };


            //add a function with callback

            var callbackTestFunc = GlobalObject.AddFunction("callbackTest");
            callbackTestFunc.Execute += (func, args) => {
                var callback = args.Arguments.FirstOrDefault(p => p.IsFunction);
                if (callback != null)
                {
                    var callbackArgs = CfrV8Value.CreateObject(new CfrV8Accessor());
                    callbackArgs.SetValue("success", CfrV8Value.CreateBool(true), CfxV8PropertyAttribute.ReadOnly);
                    callbackArgs.SetValue("text", CfrV8Value.CreateString("Message from C#"), CfxV8PropertyAttribute.ReadOnly);

                    callback.ExecuteFunction(null, new CfrV8Value[] { callbackArgs });
                }
            };


            //add a function with async callback
            var asyncCallbackTestFunc = GlobalObject.AddFunction("asyncCallbackTest");
            asyncCallbackTestFunc.Execute += async (func, args) => {
                //save current context
                var v8Context = CfrV8Context.GetCurrentContext();
                var callback = args.Arguments.FirstOrDefault(p => p.IsFunction);

                //simulate async methods.
                await Task.Delay(5000);

                if (callback != null)
                {
                    //get render process context
                    var rc = callback.CreateRemoteCallContext();

                    //enter render process
                    rc.Enter();

                    //create render task
                    var task = new CfrTask();
                    task.Execute += (_, taskArgs) =>
                    {
                        //enter saved context
                        v8Context.Enter();

                        //create callback argument
                        var callbackArgs = CfrV8Value.CreateObject(new CfrV8Accessor());
                        callbackArgs.SetValue("success", CfrV8Value.CreateBool(true), CfxV8PropertyAttribute.ReadOnly);
                        callbackArgs.SetValue("text", CfrV8Value.CreateString("Message from C#"), CfxV8PropertyAttribute.ReadOnly);

                        //execute callback
                        callback.ExecuteFunction(null, new CfrV8Value[] { callbackArgs });


                        v8Context.Exit();

                        //lock task from gc
                        lock (task)
                        {
                            Monitor.PulseAll(task);
                        }
                    };

                    lock (task)
                    {
                        //post task to render process
                        v8Context.TaskRunner.PostTask(task);
                    }

                    rc.Exit();

                    GC.KeepAlive(task);
                }


            };

            var getServers = myObject.AddFunction("getServers");
            getServers.Execute += GetServers;

            var getListSite = myObject.AddFunction("getListSite");
            getListSite.Execute += GetListSite;

            var getDetail = myObject.AddFunction("getDetail");
            getDetail.Execute += GetSiteDetail;

            var openPath = myObject.AddFunction("openPath");
            openPath.Execute += OpenPath;

        }

        private List<WebSite> GetWebSites(string address)
        {
            try
            {
                var reply = new RpcClient().GetListSite(address);
                if (reply != null && reply.Message == "success")
                {
                    var list = reply.ListWebSite.ToList();
                    return list;
                }
                else if (reply != null)//连接正常，但是服务端未正确返回结果
                {
                    MessageBox.Show(reply.Message);
                }
            }
            catch (Exception)//连接异常或服务未启动
            {
                MessageBox.Show("服务器连接异常或服务未启动！");
            }
            return new List<WebSite>();
        }

        private List<GRPCDemo.IISInfo> GetLocalSites()
        {
            return Helper.GetAllSites();
        }

        public void GetSiteDetail(object sender, CfrV8HandlerExecuteEventArgs args)
        {
            var address = args.Arguments.FirstOrDefault(p => p.IsString);
            var path = args.Arguments[1].StringValue;
            if (address != null)
            {
                if (address.StringValue.Contains("localhost"))
                {
                    var detail = Helper.GetDbDetail(path);
                    args.SetReturnValue(CfrV8Value.CreateString(JsonConvert.SerializeObject(detail)));
                    return;
                }
                try
                {
                    var reply = new RpcClient().GetSiteDetail(address.StringValue, path);
                    if (reply != null && reply.Message == "success")
                    {
                        args.SetReturnValue(CfrV8Value.CreateString(JsonConvert.SerializeObject(reply)));
                    }
                    else if (reply != null)//连接正常，但是服务端未正确返回结果
                    {
                        MessageBox.Show(reply.Message);
                    }
                }
                catch (Exception ex)//连接异常或服务未启动
                {
                    MessageBox.Show(ex.Message);
                }
            }
        }

        public void GetListSite(object sender, CfrV8HandlerExecuteEventArgs args)
        {
            var address = args.Arguments.FirstOrDefault(p => p.IsString);
            if (address.StringValue.Contains("localhost"))
            {
                var listLocalSite = GetLocalSites();
                args.SetReturnValue(CfrV8Value.CreateString(JsonConvert.SerializeObject(listLocalSite)));
                return;
            }
            var list = GetWebSites(address.StringValue);
            string array = JsonConvert.SerializeObject(list);
            args.SetReturnValue(CfrV8Value.CreateString(array));
        }

        public void OpenPath(object sender, CfrV8HandlerExecuteEventArgs args)
        {
            var type = args.Arguments[0].StringValue;
            var path = args.Arguments[1].StringValue;
            if (type == "directory" || type == "http")
            {
                Process.Start("explorer.exe", path);
            }
            else if(type == "ssms")
            {
                //string strArguments = "-S {0} -d {1} -U {2} -P {3}";
                var programPath = Common.GetAppConfig("SsmsPath");
                Process.Start(programPath, path);
            }
            else if(type == "vs")
            {
                ProcessStartInfo startInfo = new ProcessStartInfo();
                startInfo.FileName = Common.GetAppConfig("DevenvToolPath");
                var slnpath = Common.GetSlnPath(path);
                if (!string.IsNullOrEmpty(slnpath))
                {
                    var slnFiles = Directory.GetFiles(slnpath, "*.sln", SearchOption.TopDirectoryOnly);
                    if (slnFiles.Count() <= 0) return;
                    var slnValue = slnFiles[0];
                    startInfo.Arguments = slnValue; //后续调整

                    if (!File.Exists(startInfo.FileName))
                    {
                        MessageBox.Show("配置信息错误！【DevenvPath】"); return;
                    }
                    Process.Start(startInfo);
                }
            }
        }

        public void GetServers(object sender, CfrV8HandlerExecuteEventArgs args)
        {
            ConfigHelper configHelper = new ConfigHelper();
            var listServer = configHelper.ReadServers();
            args.SetReturnValue(CfrV8Value.CreateString(JsonConvert.SerializeObject(listServer)));
        }

        private void LoadHandler_OnLoadEnd(object sender, Chromium.Event.CfxOnLoadEndEventArgs e)
		{
            this.FormBorderStyle = FormBorderStyle.FixedDialog;//设置边框为不可调节
            this.MaximizeBox = false;//取消最大化按键
            this.MinimizeBox = false;//取消最小化按键
            // Check if it is the main frame when page has loaded.
            if (e.Frame.IsMain)
			{
				//Open DevTools window to watch js console output messages.

				Chromium.ShowDevTools();

                

                //call js function without return value
                //ExecuteJavascript("sayHello()");

				//call js function with return value
				//EvaluateJavascript("sayHelloToSomeone('C#')", (value, exception) =>
				//{
				//	if (value.IsString)
				//	{
				//		// Get value from Javascript.
				//		var jsValue = value.StringValue;

				//		MessageBox.Show(this, jsValue);
				//	}
				//});
			}
		}

        /// <summary>
        /// 添加双击托盘图标事件（双击显示窗口）
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (WindowState == FormWindowState.Minimized)
            {
                //还原窗体显示    
                WindowState = FormWindowState.Normal;
                this.Show();
                //激活窗体并给予它焦点
                this.Activate();
                //任务栏区显示图标
                this.ShowInTaskbar = true;
                //托盘区图标隐藏
                IIS.Visible = false;
            }
        }

        /// <summary>
        /// 确认是否退出
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void F_Main_FormClosing(object sender, FormClosingEventArgs e)
        {

            //任务栏区显示图标
            this.ShowInTaskbar = false;
            //图标显示在托盘区
            IIS.Visible = true;

            this.Hide();
            WindowState = FormWindowState.Minimized;
            e.Cancel = true;
        }

        /// <summary>
        /// 托盘右键显示主界面
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ShowToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Show();
            WindowState = FormWindowState.Normal;
        }
        /// <summary>
        /// 托盘右键退出程序
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void QuitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("是否确认退出程序？", "退出", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.OK)
            {
                // 关闭所有的线程
                this.Dispose();
                this.Close();
            }
        }

    }
}
